home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / ELVIS / REDRAW.C < prev    next >
C/C++ Source or Header  |  1992-10-01  |  21KB  |  1,000 lines

  1. /* redraw.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains functions that draw text on the screen.  The major entry
  12.  * points are:
  13.  *    redrawrange()    - called from modify.c to give hints about what parts
  14.  *              of the screen need to be redrawn.
  15.  *    redraw()    - redraws the screen (or part of it) and positions
  16.  *              the cursor where it belongs.
  17.  *    idx2col()    - converts a markidx() value to a logical column number.
  18.  */
  19.  
  20. #include "config.h"
  21. #include "vi.h"
  22.  
  23. /* This variable contains the line number that smartdrawtext() knows best */
  24. static long smartlno;
  25.  
  26. /* This function remebers where changes were made, so that the screen can be
  27.  * redraw in a more efficient manner.
  28.  */
  29. static long    redrawafter;    /* line# of first line that must be redrawn */
  30. static long    preredraw;    /* line# of last line changed, before change */
  31. static long    postredraw;    /* line# of last line changed, after change */
  32. void redrawrange(after, pre, post)
  33.     long    after;    /* lower bound of redrawafter */
  34.     long    pre;    /* upper bound of preredraw */
  35.     long    post;    /* upper bound of postredraw */
  36. {
  37.     if (after == redrawafter)
  38.     {
  39.         /* multiple insertions/deletions at the same place -- combine
  40.          * them
  41.          */
  42.         preredraw -= (post - pre);
  43.         if (postredraw < post)
  44.         {
  45.             preredraw += (post - postredraw);
  46.             postredraw = post;
  47.         }
  48.         if (redrawafter > preredraw)
  49.         {
  50.             redrawafter = preredraw;
  51.         }
  52.         if (redrawafter < 1L)
  53.         {
  54.             redrawafter = 0L;
  55.             preredraw = postredraw = INFINITY;
  56.         }
  57.     }
  58.     else if (postredraw > 0L)
  59.     {
  60.         /* multiple changes in different places -- redraw everything
  61.          * after "after".
  62.          */
  63.         postredraw = preredraw = INFINITY;
  64.         if (after < redrawafter)
  65.             redrawafter = after;
  66.     }
  67.     else
  68.     {
  69.         /* first change */
  70.         redrawafter = after;
  71.         preredraw = pre;
  72.         postredraw = post;
  73.     }
  74. }
  75.  
  76.  
  77. #ifndef NO_CHARATTR
  78. /* see if a given line uses character attribute strings */
  79. static int hasattr(lno, text)
  80.     long        lno;    /* the line# of the cursor */
  81.     REG char    *text;    /* the text of the line, from fetchline */
  82. {
  83.     static long    plno;    /* previous line number */
  84.     static long    chgs;    /* previous value of changes counter */
  85.     static int    panswer;/* previous answer */
  86.     char        *scan;
  87.  
  88.     /* if charattr is off, then the answer is "no, it doesn't" */
  89.     if (!*o_charattr)
  90.     {
  91.         chgs = 0; /* <- forces us to check if charattr is later set */
  92.         return FALSE;
  93.     }
  94.  
  95.     /* if we already know the answer, return it... */
  96.     if (lno == plno && chgs == changes)
  97.     {
  98.         return panswer;
  99.     }
  100.  
  101.     /* get the line & look for "\fX" */
  102.     if (!text[0] || !text[1] || !text[2])
  103.     {
  104.         panswer = FALSE;
  105.     }
  106.     else
  107.     {
  108.         for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
  109.         {
  110.         }
  111.         panswer = (scan[2] != '\0');
  112.     }
  113.  
  114.     /* save the results */
  115.     plno = lno;
  116.     chgs = changes;
  117.  
  118.     /* return the results */
  119.     return panswer;
  120. }
  121. #endif
  122.  
  123.  
  124.  
  125. /* This function converts a MARK to a column number.  It doesn't automatically
  126.  * adjust for leftcol; that must be done by the calling function
  127.  */
  128. int idx2col(curs, text, inputting)
  129.     MARK        curs;    /* the line# & index# of the cursor */
  130.     REG char    *text;    /* the text of the line, from fetchline */
  131.     int        inputting;    /* boolean: called from input() ? */
  132. {
  133.     static MARK    pcursor;/* previous cursor, for possible shortcut */
  134.     static MARK    pcol;    /* column number for pcol */
  135.     static long    chgs;    /* previous value of changes counter */
  136.     REG int        col;    /* used to count column numbers */
  137.     REG int        idx;    /* used to count down the index */
  138.     REG int        i;
  139.  
  140.     /* for now, assume we have to start counting at the left edge */
  141.     col = 0;
  142.     idx = markidx(curs);
  143.  
  144.     /* if the file hasn't changed & line number is the same & it has no
  145.      * embedded character attribute strings, can we do shortcuts?
  146.      */
  147.     if (chgs == changes
  148.      && !((curs ^ pcursor) & ~(BLKSIZE - 1))
  149. #ifndef NO_CHARATTR
  150.      && !hasattr(markline(curs), text)
  151. #endif
  152.     )
  153.     {
  154.         /* no movement? */
  155.         if (curs == pcursor)
  156.         {
  157.             /* return the column of the char; for tabs, return its last column */
  158.             if (text[idx] == '\t' && !inputting && !*o_list)
  159.             {
  160.                 return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
  161.             }
  162.             else
  163.             {
  164.                 return pcol;
  165.             }
  166.         }
  167.  
  168.         /* movement to right? */
  169.         if (curs > pcursor)
  170.         {
  171.             /* start counting from previous place */
  172.             col = pcol;
  173.             idx = markidx(curs) - markidx(pcursor);
  174.             text += markidx(pcursor);
  175.         }
  176.     }
  177.  
  178.     /* count over to the char after the idx position */
  179.     while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
  180.     {
  181.         if (i == '\t' && !*o_list)
  182.         {
  183.             col += *o_tabstop;
  184.             col -= col % *o_tabstop;
  185.         }
  186.         else if (i >= '\0' && i < ' ' || i == '\177')
  187.         {
  188.             col += 2;
  189.         }
  190. #ifndef NO_CHARATTR
  191.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  192.         {
  193.             text += 2; /* plus one more at bottom of loop */
  194.             idx -= 2;
  195.         }            
  196. #endif
  197.         else
  198.         {
  199.             col++;
  200.         }
  201.         text++;
  202.         idx--;
  203.     }
  204.  
  205.     /* save stuff to speed next call */
  206.     pcursor = curs;
  207.     pcol = col;
  208.     chgs = changes;
  209.  
  210.     /* return the column of the char; for tabs, return its last column */
  211.     if (*text == '\t' && !inputting && !*o_list)
  212.     {
  213.         return col + *o_tabstop - (col % *o_tabstop) - 1;
  214.     }
  215.     else
  216.     {
  217.         return col;
  218.     }
  219. }
  220.  
  221.  
  222. /* This function is similar to idx2col except that it takes care of sideways
  223.  * scrolling - for the given line, at least.
  224.  */
  225. int mark2phys(m, text, inputting)
  226.     MARK    m;        /* a mark to convert */
  227.     char    *text;        /* the line that m refers to */
  228.     int    inputting;    /* boolean: caled from input() ? */
  229. {
  230.     int    i;
  231.  
  232.     i = idx2col(m, text, inputting);
  233.     while (i < leftcol)
  234.     {
  235.         leftcol -= *o_sidescroll;
  236.         mustredraw = TRUE;
  237.         redrawrange(1L, INFINITY, INFINITY);
  238.         qaddch('\r');
  239.         /* drawtext(text); */
  240.     }
  241.     while (i > rightcol)
  242.     {
  243.         leftcol += *o_sidescroll;
  244.         mustredraw = TRUE;
  245.         redrawrange(1L, INFINITY, INFINITY);
  246.         qaddch('\r');
  247.         /* drawtext(text); */
  248.     }
  249.     physcol = i - leftcol;
  250.     physrow = markline(m) - topline;
  251.  
  252.     return physcol;
  253. }
  254.  
  255. /* This function draws a single line of text on the screen.  The screen's
  256.  * cursor is assumed to be located at the leftmost column of the appropriate
  257.  * row.
  258.  */
  259. static void drawtext(text, clr)
  260.     REG char    *text;    /* the text to draw */
  261.     int        clr;    /* boolean: do a clrtoeol? */
  262. {
  263.     REG int        col;    /* column number */
  264.     REG int        i;
  265.     REG int        tabstop;    /* *o_tabstop */
  266.     REG int        limitcol;    /* leftcol or leftcol + COLS */
  267.     int        abnormal;    /* boolean: charattr != A_NORMAL? */
  268.  
  269. #ifndef NO_SENTENCE
  270.     /* if we're hiding format lines, and this is one of them, then hide it */
  271.     if (*o_hideformat && *text == '.')
  272.     {
  273.         clrtoeol();
  274. #if OSK
  275.         qaddch('\l');
  276. #else
  277.         qaddch('\n');
  278. #endif
  279.         return;
  280.     }
  281. #endif
  282.  
  283.     /* move some things into registers... */
  284.     limitcol = leftcol;
  285.     tabstop = *o_tabstop;
  286.     abnormal = FALSE;
  287.  
  288. #ifndef CRUNCH
  289.     if (clr)
  290.         clrtoeol();
  291. #endif
  292.     /* skip stuff that was scrolled off left edge */
  293.     for (col = 0;
  294.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  295.          text++)
  296.     {
  297.         if (i == '\t' && !*o_list)
  298.         {
  299.             col = col + tabstop - (col % tabstop);
  300.         }
  301.         else if (i >= 0 && i < ' ' || i == '\177')
  302.         {
  303.             col += 2;
  304.         }
  305. #ifndef NO_CHARATTR
  306.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  307.         {
  308.             text += 2; /* plus one more as part of "for" loop */
  309.  
  310.             /* since this attribute might carry over, we need it */
  311.             switch (*text)
  312.             {
  313.               case 'R':
  314.               case 'P':
  315.                 attrset(A_NORMAL);
  316.                 abnormal = FALSE;
  317.                 break;
  318.  
  319.               case 'B':
  320.                 attrset(A_BOLD);
  321.                 abnormal = TRUE;
  322.                 break;
  323.  
  324.               case 'U':
  325.                 attrset(A_UNDERLINE);
  326.                 abnormal = TRUE;
  327.                 break;
  328.  
  329.               case 'I':
  330.                 attrset(A_ALTCHARSET);
  331.                 abnormal = TRUE;
  332.                 break;
  333.             }
  334.         }
  335. #endif
  336.         else
  337.         {
  338.             col++;
  339.         }
  340.     }
  341.  
  342.     /* adjust for control char that was partially visible */
  343.     while (col > limitcol)
  344.     {
  345.         qaddch(' ');
  346.         limitcol++;
  347.     }
  348.  
  349.     /* now for the visible characters */
  350.     for (limitcol = leftcol + COLS;
  351.          (i = *text) && col < limitcol;
  352.          text++)
  353.     {
  354.         if (i == '\t' && !*o_list)
  355.         {
  356.             i = col + tabstop - (col % tabstop);
  357.             if (i < limitcol)
  358.             {
  359. #ifdef CRUNCH
  360.                 if (!clr && has_PT && !((i - leftcol) & 7))
  361. #else
  362.                 if (has_PT && !((i - leftcol) & 7))
  363. #endif
  364.                 {
  365.                     do
  366.                     {
  367.                         qaddch('\t');
  368.                         col += 8; /* not exact! */
  369.                     } while (col < i);
  370.                     col = i; /* NOW it is exact */
  371.                 }
  372.                 else
  373.                 {
  374.                     do
  375.                     {
  376.                         qaddch(' ');
  377.                         col++;
  378.                     } while (col < i);
  379.                 }
  380.             }
  381.             else /* tab ending after screen? next line! */
  382.             {
  383.                 col = limitcol;
  384.                 if (has_AM)
  385.                 {
  386.                     addch('\n');    /* GB */
  387.                 }
  388.             }
  389.         }
  390.         else if (i >= 0 && i < ' ' || i == '\177')
  391.         {
  392.             col += 2;
  393.             qaddch('^');
  394.             if (col <= limitcol)
  395.             {
  396.                 qaddch(i ^ '@');
  397.             }
  398.         }
  399. #ifndef NO_CHARATTR
  400.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  401.         {
  402.             text += 2; /* plus one more as part of "for" loop */
  403.             switch (*text)
  404.             {
  405.               case 'R':
  406.               case 'P':
  407.                 attrset(A_NORMAL);
  408.                 abnormal = FALSE;
  409.                 break;
  410.  
  411.               case 'B':
  412.                 attrset(A_BOLD);
  413.                 abnormal = TRUE;
  414.                 break;
  415.  
  416.               case 'U':
  417.                 attrset(A_UNDERLINE);
  418.                 abnormal = TRUE;
  419.                 break;
  420.  
  421.               case 'I':
  422.                 attrset(A_ALTCHARSET);
  423.                 abnormal = TRUE;
  424.                 break;
  425.             }
  426.         }
  427. #endif
  428.         else
  429.         {
  430.             col++;
  431.             qaddch(i);
  432.         }
  433.     }
  434.  
  435.     /* get ready for the next line */
  436. #ifndef NO_CHARATTR
  437.     if (abnormal)
  438.     {
  439.         attrset(A_NORMAL);
  440.     }
  441. #endif
  442.     if (*o_list && col < limitcol)
  443.     {
  444.         qaddch('$');
  445.         col++;
  446.     }
  447. #ifdef CRUNCH
  448.     if (clr && col < limitcol)
  449.     {
  450.         clrtoeol();
  451.     }
  452. #endif
  453.     if (!has_AM || col < limitcol)
  454.     {
  455.         addch('\n');
  456.     }
  457. }
  458.  
  459.  
  460. #ifndef CRUNCH
  461. static void nudgecursor(same, scan, new, lno)
  462.     int    same;    /* number of chars to be skipped over */
  463.     char    *scan;    /* where the same chars end */
  464.     char    *new;    /* where the visible part of the line starts */
  465.     long    lno;    /* line number of this line */
  466. {
  467.     if (same > 0)
  468.     {
  469.         if (same < 5)
  470.         {
  471.             /* move the cursor by overwriting */
  472.             while (same > 0)
  473.             {
  474.                 qaddch(scan[-same]);
  475.                 same--;
  476.             }
  477.         }
  478.         else
  479.         {
  480.             /* move the cursor by calling move() */
  481.             move((int)(lno - topline), (int)(scan - new));
  482.         }
  483.     }
  484. }
  485. #endif /* not CRUNCH */
  486.  
  487. /* This function draws a single line of text on the screen, possibly with
  488.  * some cursor optimization.  The cursor is repositioned before drawing
  489.  * begins, so its position before doesn't really matter.
  490.  */
  491. static void smartdrawtext(text, lno)
  492.     REG char    *text;    /* the text to draw */
  493.     long        lno;    /* line number of the text */
  494. {
  495. #ifdef CRUNCH
  496.     move((int)(lno - topline), 0);
  497.     drawtext(text, TRUE);
  498. #else /* not CRUNCH */
  499.     static char    old[256];    /* how the line looked last time */
  500.     char        new[256];    /* how it looks now */
  501.     char        *build;        /* used to put chars into new[] */
  502.     char        *scan;        /* used for moving thru new[] or old[] */
  503.     char        *end;        /* last non-blank changed char */
  504.     char        *shift;        /* used to insert/delete chars */
  505.     int        same;        /* length of a run of unchanged chars */
  506.     int        limitcol;
  507.     int        col;
  508.     int        i;
  509.  
  510. # ifndef NO_CHARATTR
  511.     /* if this line has attributes, do it the dumb way instead */
  512.     if (hasattr(lno, text))
  513.     {
  514.         move((int)(lno - topline), 0);
  515.         drawtext(text, TRUE);
  516.         return;
  517.     }
  518. # endif
  519. # ifndef NO_SENTENCE
  520.     /* if this line is a format line, & we're hiding format lines, then
  521.      * let the dumb drawtext() function handle it
  522.      */
  523.     if (*o_hideformat && *text == '.')
  524.     {
  525.         move((int)(lno - topline), 0);
  526.         drawtext(text, TRUE);
  527.         return;
  528.     }
  529. # endif
  530.  
  531.     /* skip stuff that was scrolled off left edge */
  532.     limitcol = leftcol;
  533.     for (col = 0;
  534.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  535.          text++)
  536.     {
  537.         if (i == '\t' && !*o_list)
  538.         {
  539.             col = col + *o_tabstop - (col % *o_tabstop);
  540.         }
  541.         else if (i >= 0 && i < ' ' || i == '\177')
  542.         {
  543.             col += 2;
  544.         }
  545.         else
  546.         {
  547.             col++;
  548.         }
  549.     }
  550.  
  551.     /* adjust for control char that was partially visible */
  552.     build = new;
  553.     while (col > limitcol)
  554.     {
  555.         *build++ = ' ';
  556.         limitcol++;
  557.     }
  558.  
  559.     /* now for the visible characters */
  560.     for (limitcol = leftcol + COLS;
  561.          (i = *text) && col < limitcol;
  562.          text++)
  563.     {
  564.         if (i == '\t' && !*o_list)
  565.         {
  566.             i = col + *o_tabstop - (col % *o_tabstop);
  567.             while (col < i && col < limitcol)
  568.             {
  569.                 *build++ = ' ';
  570.                 col++;
  571.             }
  572.         }
  573.         else if (i >= 0 && i < ' ' || i == '\177')
  574.         {
  575.             col += 2;
  576.             *build++ = '^';
  577.             if (col <= limitcol)
  578.             {
  579.                 *build++ = (i ^ '@');
  580.             }
  581.         }
  582.         else
  583.         {
  584.             col++;
  585.             *build++ = i;
  586.         }
  587.     }
  588.     if (col < limitcol && *o_list)
  589.     {
  590.         *build++ = '$';
  591.         col++;
  592.     }
  593.     end = build;
  594.     while (col < limitcol)
  595.     {
  596.         *build++ = ' ';
  597.         col++;
  598.     }
  599.  
  600.     /* locate the last non-blank character */
  601.     while (end > new && end[-1] == ' ')
  602.     {
  603.         end--;
  604.     }
  605.  
  606.     /* can we optimize the displaying of this line? */
  607.     if (lno != smartlno)
  608.     {
  609.         /* nope, can't optimize - different line */
  610.         move((int)(lno - topline), 0);
  611.         for (scan = new, build = old; scan < end; )
  612.         {
  613.             qaddch(*scan);
  614.             *build++ = *scan++;
  615.         }
  616.         if (end < new + COLS)
  617.         {
  618.             clrtoeol();
  619.             while (build < old + COLS)
  620.             {
  621.                 *build++ = ' ';
  622.             }
  623.         }
  624.         smartlno = lno;
  625.         return;
  626.     }
  627.  
  628.     /* skip any initial unchanged characters */
  629.     for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
  630.     {
  631.     }
  632.     move((int)(lno - topline), (int)(scan - new));
  633.  
  634.     /* The in-between characters must be changed */
  635.     same = 0;
  636.     while (scan < end)
  637.     {
  638.         /* is this character a match? */
  639.         if (scan[0] == build[0])
  640.         {
  641.             same++;
  642.         }
  643.         else /* do we want to insert? */
  644.         if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
  645.         {
  646.             nudgecursor(same, scan, new, lno);
  647.             same = 0;
  648.  
  649.             insch(*scan);
  650.             for (shift = old + COLS; --shift > build; )
  651.             {
  652.                 shift[0] = shift[-1];
  653.             }
  654.             *build = *scan;
  655.         }
  656.         else /* do we want to delete? */
  657.         if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
  658.         {
  659.             nudgecursor(same, scan, new, lno);
  660.             same = 0;
  661.  
  662.             delch();
  663.             same++;
  664.             for (shift = build; shift < old + COLS - 1; shift++)
  665.             {
  666.                 shift[0] = shift[1];
  667.             }
  668.             *shift = ' ';
  669.         }
  670.         else /* we must overwrite */
  671.         {
  672.             nudgecursor(same, scan, new, lno);
  673.             same = 0;
  674.  
  675.             addch(*scan);
  676.             *build = *scan;
  677.         }
  678.  
  679.         build++;
  680.         scan++;
  681.     }
  682.  
  683.     /* maybe clear to EOL */
  684.     while (build < old + COLS && *build == ' ')
  685.     {
  686.         build++;
  687.     }
  688.     if (build < old + COLS)
  689.     {
  690.         nudgecursor(same, scan, new, lno);
  691.         same = 0;
  692.  
  693.         clrtoeol();
  694.         while (build < old + COLS)
  695.         {
  696.             *build++ = ' ';
  697.         }
  698.     }
  699. #endif /* not CRUNCH */
  700. }
  701.  
  702.  
  703. /* This function is used in visual mode for drawing the screen (or just parts
  704.  * of the screen, if that's all thats needed).  It also takes care of
  705.  * scrolling.
  706.  */
  707. void redraw(curs, inputting)
  708.     MARK    curs;        /* where to leave the screen's cursor */
  709.     int    inputting;    /* boolean: being called from input() ? */
  710. {
  711.     char        *text;        /* a line of text to display */
  712.     static long    chgs;        /* previous changes level */
  713.     long        l;
  714.     int        i;
  715.  
  716.     /* if curs == MARK_UNSET, then we should reset internal vars */
  717.     if (curs == MARK_UNSET)
  718.     {
  719.         if (topline < 1 || topline > nlines)
  720.         {
  721.             topline = 1L;
  722.         }
  723.         else
  724.         {
  725.             move(LINES - 1, 0);
  726.             clrtoeol();
  727.         }
  728.         leftcol = 0;
  729.         mustredraw = TRUE;
  730.         redrawafter = INFINITY;
  731.         preredraw = 0L;
  732.         postredraw = 0L;
  733.         chgs = 0;
  734.         smartlno = 0L;
  735.         return;
  736.     }
  737.  
  738.     /* figure out which column the cursor will be in */
  739.     l = markline(curs);
  740.     text = fetchline(l);
  741.     mark2phys(curs, text, inputting);
  742.  
  743.     /* adjust topline, if necessary, to get the cursor on the screen */
  744.     if (l >= topline && l <= botline)
  745.     {
  746.         /* it is on the screen already */
  747.  
  748.         /* if the file was changed but !mustredraw, then redraw line */
  749.         if (chgs != changes && !mustredraw)
  750.         {
  751.             smartdrawtext(text, l);
  752.         }
  753.     }
  754.     else if (l < topline && l > topline - LINES && (has_SR || has_AL))
  755.     {
  756.         /* near top - scroll down */
  757.         if (!mustredraw)
  758.         {
  759.             move(0,0);
  760.             while (l < topline)
  761.             {
  762.                 topline--;
  763.                 if (has_SR)
  764.                 {
  765.                     do_SR();
  766.                 }
  767.                 else
  768.                 {
  769.                     insertln();
  770.                 }
  771.                 text = fetchline(topline);
  772.                 drawtext(text, FALSE);
  773.                 do_UP();
  774.             }
  775.  
  776.             /* blank out the last line */
  777.             move(LINES - 1, 0);
  778.             clrtoeol();
  779.         }
  780.         else
  781.         {
  782.             topline = l;
  783.             redrawafter = INFINITY;
  784.             preredraw = 0L;
  785.             postredraw = 0L;
  786.         }
  787.     }
  788.     else if (l > topline && l < botline + LINES)
  789.     {
  790.         /* near bottom -- scroll up */
  791.         if (!mustredraw
  792. #if 1
  793.          || redrawafter == preredraw && preredraw == botline && postredraw == l
  794. #endif
  795.         )
  796.         {
  797.             move(LINES - 1,0);
  798.             clrtoeol();
  799.             while (l > botline)
  800.             {
  801.                 topline++; /* <-- also adjusts botline */
  802.                 text = fetchline(botline);
  803.                 drawtext(text, FALSE);
  804.             }
  805.             mustredraw = FALSE;
  806.         }
  807.         else
  808.         {
  809.             topline = l - (LINES - 2);
  810.             redrawafter = INFINITY;
  811.             preredraw = 0L;
  812.             postredraw = 0L;
  813.         }
  814.     }
  815.     else
  816.     {
  817.         /* distant line - center it & force a redraw */
  818.         topline = l - (LINES / 2) - 1;
  819.         if (topline < 1)
  820.         {
  821.             topline = 1;
  822.         }
  823.         mustredraw = TRUE;
  824.         redrawafter = INFINITY;
  825.         preredraw = 0L;
  826.         postredraw = 0L;
  827.     }
  828.  
  829.     /* Now... do we really have to redraw? */
  830.     if (mustredraw)
  831.     {
  832.         /* If redrawfter (and friends) aren't set, assume we should
  833.          * redraw everything.
  834.          */
  835.         if (redrawafter == INFINITY)
  836.         {
  837.             redrawafter = 0L;
  838.             preredraw = postredraw = INFINITY;
  839.         }
  840.  
  841.         /* adjust smartlno to correspond with inserted/deleted lines */
  842.         if (smartlno >= redrawafter)
  843.         {
  844.             if (smartlno < preredraw)
  845.             {
  846.                 smartlno = 0L;
  847.             }
  848.             else
  849.             {
  850.                 smartlno += (postredraw - preredraw);
  851.             }
  852.         }
  853.  
  854.         /* should we insert some lines into the screen? */
  855.         if (preredraw < postredraw && preredraw <= botline)
  856.         {
  857.             /* lines were inserted into the file */
  858.  
  859.             /* decide where insertion should start */
  860.             if (preredraw < topline)
  861.             {
  862.                 l = topline;
  863.             }
  864.             else
  865.             {
  866.                 l = preredraw;
  867.             }
  868.  
  869.             /* insert the lines... maybe */
  870.             if (l + postredraw - preredraw > botline || !has_AL)
  871.             {
  872.                 /* Whoa!  a whole screen full - just redraw */
  873.                 preredraw = postredraw = INFINITY;
  874.             }
  875.             else
  876.             {
  877.                 /* really insert 'em */
  878.                 move((int)(l - topline), 0);
  879.                 for (i = postredraw - preredraw; i > 0; i--)
  880.                 {
  881.                     insertln();
  882.                 }
  883.  
  884.                 /* NOTE: the contents of those lines will be
  885.                  * drawn as part of the regular redraw loop.
  886.                  */
  887.  
  888.                 /* clear the last line */
  889.                 move(LINES - 1, 0);
  890.                 clrtoeol();
  891.             }
  892.         }
  893.  
  894.         /* do we want to delete some lines from the screen? */
  895.         if (preredraw > postredraw && postredraw <= botline)
  896.         {
  897.             if (preredraw > botline || !has_DL)
  898.             {
  899.                 postredraw = preredraw = INFINITY;
  900.             }
  901.             else /* we'd best delete some lines from the screen */
  902.             {
  903.                 /* clear the last line, so it doesn't look
  904.                  * ugly as it gets pulled up into the screen
  905.                  */
  906.                 move(LINES - 1, 0);
  907.                 clrtoeol();
  908.  
  909.                 /* delete the lines */
  910.                 move((int)(postredraw - topline), 0);
  911.                  for (l = postredraw;
  912.                      l < preredraw && l <= botline;
  913.                      l++)
  914.                 {
  915.                     deleteln();
  916.                 }
  917.  
  918.                 /* draw the lines that are now newly visible
  919.                  * at the bottom of the screen
  920.                  */
  921.                 i = LINES - 1 + (postredraw - preredraw);
  922.                 move(i, 0);
  923.                 for (l = topline + i; l <= botline; l++)
  924.                 {
  925.                     /* clear this line */
  926.                     clrtoeol();
  927.  
  928.                     /* draw the line, or ~ for non-lines */
  929.                     if (l <= nlines)
  930.                     {
  931.                         text = fetchline(l);
  932.                         drawtext(text, FALSE);
  933.                     }
  934.                     else
  935.                     {
  936.                         addstr("~\n");
  937.                     }
  938.                 }
  939.             }
  940.         }
  941.  
  942.         /* redraw the current line */
  943.         l = markline(curs);
  944.         pfetch(l);
  945.         smartdrawtext(ptext, l);
  946.  
  947.         /* decide where we should start redrawing from */
  948.         if (redrawafter < topline)
  949.         {
  950.             l = topline;
  951.         }
  952.         else
  953.         {
  954.             l = redrawafter;
  955.         }
  956.         move((int)(l - topline), 0);
  957.  
  958.         /* draw the other lines */
  959.         for (; l <= botline && l < postredraw; l++)
  960.         {
  961.             /* we already drew the current line, so skip it now */
  962.             if (l == smartlno)
  963.             {
  964. #if OSK
  965.                 qaddch('\l');
  966. #else
  967.                 qaddch('\n');
  968. #endif
  969.                 continue;
  970.             }
  971.  
  972.             /* draw the line, or ~ for non-lines */
  973.             if (l <= nlines)
  974.             {
  975.                 text = fetchline(l);
  976.                 drawtext(text, TRUE);
  977.             }
  978.             else
  979.             {
  980.                 qaddch('~');
  981.                 clrtoeol();
  982.                 addch('\n');
  983.             }
  984.         }
  985.  
  986.         mustredraw = FALSE;
  987.     }
  988.  
  989.     /* force total (non-partial) redraw next time if not set */
  990.     redrawafter = INFINITY;
  991.     preredraw = 0L;
  992.     postredraw = 0L;
  993.  
  994.     /* move the cursor to where it belongs */
  995.     move((int)(markline(curs) - topline), physcol);
  996.     wqrefresh(stdscr);
  997.  
  998.     chgs = changes;
  999. }
  1000.